#ifndef __SCENE_NODE_H__
#define __SCENE_NODE_H__

#include "RenderingConfig.h"
#include "SceneObject.h"

namespace Nezha
{

#define DEFAULT_SCENE_LAYER 0x1

	class SceneGraph;

	/** Scene Spatial & Hierarchy.
	@REMARKS
		Scene node should have no render object.
	*/
	class GRAPHICS_ENTRY SceneNode : public ControlledObject
	{
	public:
		virtual ~SceneNode();

		const Vector3& getPosition() const;
		const Vector3& getScale() const;
		const Quaternion& getOrientation() const;

		const Vector3& getWorldPos() const;
		const Vector3& getWorldSale() const;
		const Quaternion& getWorldOrientation() const;

		void setPosition(const Vector3& pos);
		void setOrientation(const Quaternion& q);
		void setScale(const Vector3& scale);
		void translate(const Vector3& trans, bool localSpace = true);
		void rotate(const Matrix3x3& rotMat, bool localSpace = true);
		void rotate(const Quaternion& quat, bool localSpace = true);

		const Matrix4x4& getWorldTransform() const;

		u32 getTransformNBoundUpdateFlag() const;

		void updateTransform(float dt, u32 flag = TransformUpdateBits);
		void updateBound(u32 flag = BoundUpdateBits);

		//void update(u32 filter = 0);

		u16 getSceneLayer() const;

		// hierarchy
		u32 getNumChildren() const;
		SceneNode* getChild(u32 i);
		SceneNode* getChild(const _string& name);
		void attachChild(SceneNode* child);
		void removeChild(SceneNode* child);
		void removeChild(const _string& name);
		void removeAllChild();

		SceneNode(const _string& name);

		SceneObject* getBindedObject();
		SceneNode* getParentSceneNode();

		/** bind scene object.
			bind NULL to detach binded object.
		*/
		void bindOject(SceneObject* obj);
	protected:
		virtual void _updateTransform(float dt);
		virtual void _updateBound();
		virtual bool preAttachChild(SceneNode* t);
		virtual void onAttachChild(SceneNode* t);
		virtual void onRemoveChild(SceneNode* t);

		void updateBoundUpward();

		// transform
		// local space
		Vector3 mPosition;
		Vector3 mScale;
		Quaternion mOrientation;

		// world space
		Vector3 mWorldPos;
		Vector3 mWorldScale;
		Quaternion mWorldOrientation;
		mutable Matrix4x4 mHMatrixL2W;
		mutable u32 mTransformNBoundUpdateFlag;

		u32 mSceneLayer;
		PArray<SceneNode*> mChildren;

		SceneObjectPtr mBindedObject;
		SceneNode* mParentSceneNode;
	};

	inline u32 SceneNode::getTransformNBoundUpdateFlag() const
	{
		return mTransformNBoundUpdateFlag;
	}

	inline const Vector3& SceneNode::getPosition() const
	{
		return mPosition;
	}

	inline const Vector3& SceneNode::getScale() const
	{
		return mScale;
	}

	inline const Quaternion& SceneNode::getOrientation() const
	{
		return mOrientation;
	}

	inline const Vector3& SceneNode::getWorldPos() const
	{
		return mWorldPos;
	}
	inline const Vector3& SceneNode::getWorldSale() const
	{
		return mWorldScale;
	}

	inline const Quaternion& SceneNode::getWorldOrientation() const
	{
		return mWorldOrientation;
	}

	inline u32 SceneNode::getNumChildren() const
	{
		return mChildren.size();
	}

	inline u16 SceneNode::getSceneLayer() const
	{
		return mSceneLayer;
	}

	inline SceneObject* SceneNode::getBindedObject()
	{
		return mBindedObject.get();
	}

	inline SceneNode* SceneNode::getParentSceneNode()
	{
		return mParentSceneNode;
	}

	typedef RefCountedPtr<SceneNode>::Default SceneNodePtr;

}//end namespace Nezha

#endif //end __SCENE_NODE_H__